package com.xuecheng.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.sun.org.apache.regexp.internal.RE;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageResult;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.domain.cms.response.CmsPostPageResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.manage_cms.config.RabbitMqConfig;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsSiteRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import jdk.internal.org.objectweb.asm.Handle;
import lombok.experimental.var;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.bson.types.ObjectId;
import org.mockito.internal.util.io.IOUtil;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;
import sun.java2d.cmm.CMSManager;

import javax.print.DocFlavor;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
public class CmsPageService {
    @Autowired
    GridFSBucket gridFSBucket;
   /* @Autowired
    GridFsResource gridFsResource;*/
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    CmsPageRepository cmsPageRepository;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    CmsTemplateRepository cmsTemplateRepository;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    CmsSiteRepository cmsSiteRepository;

    //分页查询
    public QueryResponseResult findlist(int page, int size, QueryPageResult queryPageResult) {
       /* if (queryPageResult ==null){
            queryPageResult = new QueryPageResult();
        }*/
        //条件匹配器 自定义别名进行模糊查询
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());
        //条件值
        CmsPage cmsPage = new CmsPage();

        //判断站点ID
        if (StringUtils.isNotEmpty(queryPageResult.getSiteId())) {
            cmsPage.setSiteId(queryPageResult.getSiteId());
        }
        //判断模板id
        /*if (StringUtils.isNotEmpty(queryPageResult.getTemplateId())) {
            cmsPage.setTemplateId(queryPageResult.getTemplateId());
        }*/
        //判断别名
        if (StringUtils.isNotEmpty(queryPageResult.getPageAliase())) {
            cmsPage.setPageAliase(queryPageResult.getPageAliase());
        }
        //创建条件实例
        Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);

        //因为service接收是从第0页开始 ，但是这样不符合用户习惯 所以 我们选从第一页开始
        //但是传输数据的时候需要减1
        page = page - 1;

        //分页对象
        Pageable pageable = new PageRequest(page, size);
        //分页查询 查询到的数据
        Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);
        //总页数 数据 封装
        QueryResult<CmsPage> cmsPageQueryResult = new QueryResult<>();
        //封装数据
        cmsPageQueryResult.setList(all.getContent());
        cmsPageQueryResult.setTotal(all.getTotalElements());
        //返回结果
        return new QueryResponseResult(CommonCode.SUCCESS, cmsPageQueryResult);
    }

    //新增页面
    public CmsPageResult add(CmsPage cmsPage) {
        //调用dao 完成新增页面 完成校验需要先调用dao的查询方法（需要自定义）
        //在此之前需要先校验 页面的唯一性 通过结合页面id 模板id 页面名称可以确定唯一性
        if (cmsPage == null) {

            //抛出非法参数异常
        }
        CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if (cmsPage1 != null) {
            //抛出页面名称已经存在的异常
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        }
        cmsPage.setPageId(null);//添加页面主键有spring boot自动生成
        CmsPage save = cmsPageRepository.save(cmsPage);
        return new CmsPageResult(CommonCode.SUCCESS, cmsPage);

    }

    //根据id查询页面
    public CmsPage getById(String id) {
        //dao里自动继承了findBy方法
        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        //标准化判断是否为空
        if (optional.isPresent()) {
            return optional.get();//如果为空 就获得数据
        }
        return null;
    }

    //更新页面信息 修改页面
    public CmsPageResult update(String id, CmsPage cmsPage) {
        //现根据页面查询信息调用上面的方法
        CmsPage one = this.getById(id);
        if (one != null) {
            //查到数据信息后修改 如果没查到就是添加不是修改了 所以判断不为空
            //更新模板id
            one.setTemplateId(cmsPage.getTemplateId());
            //更新所属站点
            one.setSiteId(cmsPage.getSiteId());
            //更新页面别名
            one.setPageAliase(cmsPage.getPageAliase());
            //更新页面名称
            one.setPageName(cmsPage.getPageName());
            //更新访问路径
            one.setPageWebPath(cmsPage.getPageWebPath());
            //更新物理路径
            one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            one.setDataUrl(cmsPage.getDataUrl());
            //设置了之后执行更新
            CmsPage save = cmsPageRepository.save(one);
            if (save != null) {
                //更新成功 返回状态信息
                CmsPageResult cmsPageResult = new CmsPageResult(CommonCode.SUCCESS, save);
                return cmsPageResult;
            }

        }
        return new CmsPageResult(CommonCode.FAIL, null);
    }
    //页面静态化方法
    public String getPageHtml(String pageId) {
        //获取页面模型数据
        Map modelByPageId = this.getModelByPageId(pageId);
        if (modelByPageId == null) {
            //获取页面模型数据为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        //获取页面模板
        String templateByPageId = getTemplateByPageId(pageId);
        if (StringUtils.isEmpty(templateByPageId)){
            //页面模板为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //执行静态hua  两者整合
        String html = generateHtml(templateByPageId,modelByPageId);
        return html;
    }

    public String generateHtml(String templateComtent,Map model ){
        //创建配置对象
        Configuration configuration = new Configuration(Configuration.getVersion());
        //创建模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateComtent);
        //向configuration配置模板加载器
        configuration.setTemplateLoader(stringTemplateLoader);
        //获取模板
        try {
            Template template = configuration.getTemplate("template");
            //调用api进行静态化
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            return content;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
    //获取页面模型数据  根据dataUrl查询真正的 数据
    private Map getModelByPageId(String id) {
        //查询页面信息
        CmsPage cmsPage = this.getById(id);
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXSITS);
        }
        //取出dataUrl
        String dataUrl = cmsPage.getDataUrl();
        if (StringUtils.isEmpty(dataUrl)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);

        }
        ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);//获取url 并以map格式输出
        Map body = forEntity.getBody();
        return body;

    }

    //获取页面模板
    public String getTemplateByPageId(String id) {
        //查询页面信息
        CmsPage cmsPage = this.getById(id);
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXSITS);
        }
        String templateId = cmsPage.getTemplateId();
        if (templateId == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //根据ID查询模型数据
        Optional<CmsTemplate> byId = cmsTemplateRepository.findById(templateId);
        if (byId.isPresent()) {
            CmsTemplate cmsTemplate = byId.get();
            //模板文件id
            String templateFileId = cmsTemplate.getTemplateFileId();
            //取出模板文件的内容
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
            //打开下载流对象
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
            try {
                String string = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
                return string;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
}

    //页面发布生产方
    public ResponseResult postPage(String pageId){

        //执行静态化
        String pageHtml = this.getPageHtml(pageId);
        if (StringUtils.isEmpty(pageHtml)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //将静态化文件存储到gridFs中
        CmsPage cmsPage = saveHtml(pageId,pageHtml);

        //发送mq消息
        this.sendPostPage(pageId);
        return new ResponseResult(CommonCode.SUCCESS);


    }
    //向mq发消息
    private void sendPostPage(String pageId){
        //获取页面对象
        CmsPage cmsPage = this.getById(pageId);
        if (cmsPage==null){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        //拼装消息对象
        Map<String,String> map = new HashMap<>();
        map.put("pageId", pageId);
        //转成json串
        String jsonString = JSON.toJSONString(map);
        //得到站点id
        String siteId = cmsPage.getSiteId();

        //发送mq
        //向mq发消息 指定交换机  站点id作为routingKey
        rabbitTemplate.convertAndSend(RabbitMqConfig.EX_ROUTING_CMS_POSTPAGE,siteId,jsonString);
    }

    //保存静态化页面内容
    public CmsPage saveHtml(String pageId,String content){
        //查询页面 得到页面信息
        CmsPage cmsPage = this.getById(pageId);
        if (cmsPage==null){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        ObjectId objectId = null;
        //将htmlcontent内容转成输入流
        try {
            InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
            //将html文件保存到GridFS中  得到输入流和页面名称
             objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());

        } catch (IOException e) {
            e.printStackTrace();
        }
        //将html文件id保存到cmsPage中
        cmsPage.setHtmlFileId(objectId.toHexString());
        cmsPageRepository.save(cmsPage);
        return cmsPage;
    }

    //为一键发布页面服务
    //   //保存页面，有则更新，没有则添加
    public CmsPageResult save(CmsPage cmsPage) {  //模板
        //判断页面是否存在
        CmsPage one = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if(one!=null){
            //进行更新
            return this.update(one.getPageId(),cmsPage);
        }
        return this.add(cmsPage);

    }
    //一键发布页面
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        //将页面信息存储到cmspage中
        CmsPageResult save = this.save(cmsPage);
        if (!save.isSuccess()){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        //得到页面id
        CmsPage cmsPageSave = save.getCmsPage();
        String pageId = cmsPageSave.getPageId();
        //执行页面静态化 存到gridfs中 mq发消息 传达下载命令
        ResponseResult responseResult = this.postPage(pageId);
        if (!responseResult.isSuccess()){
             ExceptionCast.cast(CommonCode.FAIL);
        }
        //拼接url url =PageNameAndSiteIdAndPageWebPath
        //先取出站点id
        String siteId = cmsPageSave.getSiteId();
        //拿到站点对应的信息
        CmsSite cmsSite = this.findCmsSiteById(siteId);
        String pageName = cmsPageSave.getPageName();
        String pageUrl = cmsSite.getSiteDomain() + cmsSite.getSiteWebPath() + cmsPageSave.getPageWebPath() + pageName;
        return new CmsPostPageResult(CommonCode.SUCCESS,pageUrl);

    }
    //根据站点id查询站点信息 单独封出来的一个方法
    //根据站点id查询站点信息
    public CmsSite findCmsSiteById(String siteId){
        Optional<CmsSite> optional = cmsSiteRepository.findById(siteId);
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }


}